#!/usr/bin/env python3

# Copyright (c) 2020-2021 Fpemud <fpemud@sina.com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.


import json
import pathlib
from ._const import Const
from ._errors import ConfigError


class Config:

    DEFAULT_UPDATE_TIMEOUT = 3                  # 3 seconds

    DEFAULT_RETRY_COUNT = 3

    DEFAULT_RETRY_WAIT = 3                      # 3 seconds

    def __init__(self):
        cfg = None
        backendDict = None
        if True:
            # FIXME: there's no way for user config to disable some value in system config
            cfg, backendDict = self._readCfgFile(Const.getCfgFileFullfn(True))
            if "__builtin" in backendDict:
                raise ConfigError('invalid section "__builtin" in config file "%s"' % (Const.getCfgFileFullfn(True)))

            cfg2, backendDict2 = self._readCfgFile(Const.getCfgFileFullfn(False))
            if "__builtin" in backendDict2:
                raise ConfigError('invalid section "__builtin" in config file "%s"' % (Const.getCfgFileFullfn(False)))

            cfg.update(cfg2)
            backendDict.update(backendDict2)

        self._updateTimeout = self.DEFAULT_UPDATE_TIMEOUT
        if "update-timeout" in cfg:
            self._updateTimeout = cfg["update-timeout"]
            if not isinstance(self._updateTimeout, int):
                raise ConfigError('invalid value for "update-timeout" property')
            if self._updateTimeout <= 0:
                raise ConfigError('invalid value for "update-timeout" property')

        self._retryCount = self.DEFAULT_RETRY_COUNT
        if "retry-count" in cfg:
            self._retryCount = cfg["retry-count"]
            if not isinstance(self._retryCount, int):
                raise ConfigError('invalid value for "retry-count" property')
            if self._retryCount < 0:
                raise ConfigError('invalid value for "retry-count" property')

        self._retryWait = self.DEFAULT_RETRY_WAIT
        if "retry-wait" in cfg:
            self._retryWait = cfg["retry-wait"]
            if not isinstance(self._retryWait, int):
                raise ConfigError('invalid value for "retry-wait" property')
            if self._retryWait < 0:
                raise ConfigError('invalid value for "retry-wait" property')

        self._backendDict = backendDict
        if True:
            self._backendDict["__builtin"] = {
                "type": "local-dir",
                "param": {
                    "path": "/usr/share/mrget"
                }
            }

    def get_backend_dict(self):
        return self._backendDict

    def get_update_timeout(self):
        return self._updateTimeout

    def get_retry_count(self):
        return self._retryCount

    def get_retry_wait(self):
        return self._retryWait

    def _readCfgFile(self, fullfn):
        cfg = {}
        backendDict = {}

        try:
            currentSection = None
            for i, line in enumerate(pathlib.Path(fullfn).read_text().split("\n") + [""]):
                if currentSection is None:
                    line = line.strip()
                    if line == "" or line.startswith('#'):
                        continue
                    if line.startswith('[') and line.endswith(']'):
                        currentSection = line[1:-1]
                        currentSectionContent = ""
                        continue
                    raise ConfigError('invalid line %d in config file "%s"' % (i + 1, fullfn))
                else:
                    if len(line.strip()) != 0:
                        currentSectionContent += line
                    else:
                        if currentSection == "main":
                            cfg = json.loads(currentSectionContent)
                        else:
                            tlist = currentSection.split(':')
                            if len(tlist) != 2 or tlist[0] != "backend":
                                raise ConfigError('invalid section "%s" in config file "%s"' % (currentSection, fullfn))
                            try:
                                backendDict[tlist[1]] = json.loads(currentSectionContent)
                            except json.JSONDecodeError:
                                raise ConfigError('invalid section "%s" in config file "%s"' % (currentSection, fullfn))
                        currentSection = None
                        del currentSectionContent
            if currentSection is not None:
                raise ConfigError('invalid content in config file "%s"' % (fullfn))
        except FileNotFoundError:
            pass

        return (cfg, backendDict)
